-- TreasureM
-- Created by chendh
-- 海盗宝藏模块

module("TreasureM", package.seeall);

local treasureBonus = {};
local treasureGroup = {};
local sort_id_list  = {};

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    treasureBonus = {};
    treasureGroup = {};

    -- 转换下treasure_bonus信息表
    local configTable = get_treasure_bonus_CSV();
    for i = 1, #configTable do
        local id   = configTable[i].id;
        treasureBonus[id] = configTable[i];

        if type(treasureBonus[id].group) == "string" and string.len(treasureBonus[id].group) > 0 then

            if not treasureGroup[treasureBonus[id].group] then
                treasureGroup[treasureBonus[id].group] = {}
            end
            table.insert(treasureGroup[treasureBonus[id].group], id);
        end
    end

    -- 排序一把
    sort_id_list = table.keys(treasureBonus);
    table.sort(sort_id_list);

    configTable = {};
end

function init()
    loadCsv();
end

-- 检索奖励
function queryBonus(id, path)
    local m = treasureBonus[id];

    if not m or not path then
        return m;
    end

    return m[path];
end

-- 抽取奖励id
function extractTreasure()
    local arr = {};
    local rand = DungeonM.getRandSeed("treasure bonus");
    local sum = 0;
    local bonus;

    for index = 1, #sort_id_list do
        info = treasureBonus[sort_id_list[index]];
        if treasureFilter(info.id) then
            table.insert(arr, info);
        end
    end

    -- 根据权重抽取
    for index = 1, #arr do
        sum = sum + arr[index]["ratio"];
    end
    rand = rand % sum;

    sum = 0;
    for index = 1, #arr do
        sum = sum + arr[index]["ratio"];
        if (sum > rand) then
            return arr[index]["id"];
        end
    end

    assert(0, "不应该走到这里。");
end

-- 宝藏过滤
function treasureFilter(classId)
    local info = treasureBonus[classId];

    if not info then
        return false;
    end

    local number = info.times;

    if not number then
        return false;
    end

    -- 判断所处的地牢是否符合要求
    local currDungeonId = DungeonM.getDungeonId();

    if type(info.chapter) == "number" and info.chapter > 0 then
        if info.chapter ~= DungeonAreaM.getParentId(currDungeonId) then
            -- 玩家不在宝藏要求的副本章节中
            return false;
        end
    end

    if number ~= NUMBER_INFINITY then
        local treasure_stat = ME.user.dbase:query("treasure_stat");
        local total = 0;

        if treasure_stat then
            total = total + (treasure_stat[classId] or 0);
        end

        -- 这个宝藏的出现次数已满
        if total >= number then
            return false;
        end

        -- 进行宝藏分组的总次数限制判断
        local group = info.group;
        if type(group) == "string" and string.len(group) > 0 then
            local groupMaxTimes = FormulaM.invoke("CALC_TREASURE_GROUP_TIMES", group);
            local groupTimes = 0;
            for _,id in ipairs(treasureGroup[group]) do
                groupTimes = groupTimes + (treasure_stat[id] or 0);

                if groupTimes >= groupMaxTimes then
                    return false;
                end
            end
        end

    end

    -- 限量钻石的次数判断
    if info["dbase"]["limited_gem"] then
        local gemMaxTimes = info["dbase"]["limited_gem"];
        local buffId = info["dbase"]["buff_id"];

        -- 必须配置buff_id
        if not buffId then
            return false;
        end

        -- 次数超过了
        if BuffDataM.query("limited_gem", buffId) >= gemMaxTimes then
            return false;
        end
    end

    return true;
end

-- 抽取奖励
function calcBonus(bonusId)
    local bonus = queryBonus(bonusId, "bonus");

    if type(bonus) == "table" then
        return bonus;
    end

    if  type(bonus) == "string" and
        string.startWith(bonus, "formula_") then
        local formula = string.sub(bonus, string.len("formula_") + 1);
        return FormulaM.invoke(formula, bonusId);
    end

    -- 不应该走到这里
    assert(false, "村民奖励配置错误。");
end

-- 判断能否领取奖励
function canTakeBonus(pos)
    local grid = DungeonM.getGridByPos(pos);
    -- 如果不是宝藏
    if grid.type ~= GRID_TYPE_TREASURE then
        trace("treasureM", "格子%d不是海盗的宝藏。");
        return false;
    end

    -- 格子还未翻开
    if not grid:isOpened() then
        trace("treasureM", "格子%d尚未翻开。");
        return false;
    end

    -- 如果宝藏已经失效了
    if grid.state == GRID_STATE_DISABLE then
        trace("treasureM", "宝藏已经失效了。");
        return false;
    end

    return DungeonM.isAllMonsterDead();
end

-- 领取村民奖励
function takeBonus(pos)
    -- 判断
    if not canTakeBonus(pos) then
        return false;
    end

    local grid = DungeonM.getGridByPos(pos);
    local bonusId = extractTreasure();
    local arr = calcBonus(bonusId);

    trace("treasureM", "领取海贼宝藏%d的奖励。", bonusId);

    -- 格子状态
    grid:changeState(GRID_STATE_DISABLE);

    -- 记录下获取次数
    addTreasureStat(bonusId);

    for _, bonus in pairs(arr) do
        BonusM.doBonus(bonus, "treasure_bonus");
    end

    EventMgr.fire(event.TREASURE_BONUS, {["pos"] = pos, ["bonus"] = arr, });

    -- 海贼王专属发动特效
    local prop = PropM.combine(ME.user, "treasure", 1);
    if prop[3] > 0 then
        -- 触发特技发动事件
        EventMgr.fire(event.SPECIAL_SKILL_TRIGGER, { propId = prop[1] });
    end

    -- 返回奖励列表，用于提示
    return true;
end

-- 记录下获取次数
function addTreasureStat(treasureId)
    local treasureStat = ME.user.dbase:query("treasure_stat", {});

    treasureStat[treasureId] = 1 + (treasureStat[treasureId] or 0);

    ME.user.dbase:set("treasure_stat", treasureStat);

    -- 统计限量钻石的次数
    local info = treasureBonus[treasureId];
    if info["dbase"]["limited_gem"] then
        local buffId = info["dbase"]["buff_id"];
        local times = BuffDataM.query("limited_gem", buffId);

        BuffDataM.set("limited_gem", buffId, times + 1);
    end
end

-- 获取奖励描述
function getBonusDesc(bonus)
    local desc = getLocStr("get_pirate_treasure");

    -- 根据传入的奖励信息，获取描述
    local bonusDesc = "";
    local seperator = "";

    for i, v in pairs(bonus) do
        -- 拼接奖励信息
        if i ~= 1 then
            seperator = getLocStr("seperator");
        end

        if v[1] == 1 then
            -- 道具奖励
            bonusDesc = bonusDesc .. seperator .. string.format("%s+%d", ItemM.query(v[2], "name"), v[3]);
        elseif v[1] == 2 then
            -- 属性奖励
            bonusDesc = bonusDesc .. seperator .. string.format("%s+%d", FieldsM.getFieldName(v[2]), v[3]);
        end
    end

    return desc .. "\n" .. bonusDesc;
end
